#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "r_socket_common.h"
#include "r_socket_ipv4_tcp_partner.h"
#include "r_socket_obj_manager.h"

#include "utilities/string_operator.h"
#include "utilities/r_logger.h"

namespace eniac
{

r_socket_proxy_ret_t r_socket_ipv4_tcp_partner::read_message(const r_socket::ptr socket_obj, r_socket_message::ptr& message)
{
    if (nullptr == socket_obj.get())
    {
        LOG_WRN() << "Socket object is NULL";
        return r_socket_proxy_ret_t::NULL_PTR;
    }

    if (socket_obj->m_socket_fd == INVALID_SOCKET_FD)
    {
        LOG_WRN() << "Socket FD is INVALID";
        return r_socket_proxy_ret_t::INVALID_SOCKET_FD;
    }

    uint64_t readable_bytes = r_socket_common::get_readable_bytes_length(socket_obj->m_socket_fd);
    if (0 == readable_bytes)
    {
        LOG_WRN() << "No data can be read, the remote socket has closed";
        return r_socket_proxy_ret_t::NO_DATA_CAN_BE_READ;
    }

    message = r_socket_message::create_obj();
    message->m_socket_id = socket_obj->m_socket_id;
    message->m_payload.resize(readable_bytes);

    ssize_t valread = read(socket_obj->m_socket_fd, message->m_payload.data(), message->m_payload.size());
    if (valread <= 0)
    {
        LOG_WRN() << "No data can be read, the remote socket has closed(read)";
        message.reset();
        return r_socket_proxy_ret_t::TO_READ_DATA_FROME_SOCKET_IS_FAILED;
    }

    LOG_DBG() << "Read " << message->m_payload.size() << " bytes";
    return r_socket_proxy_ret_t::OK;
}

r_socket_proxy_ret_t r_socket_ipv4_tcp_partner::send_message(const r_socket::ptr socket_obj, const std::vector<uint8_t>& message)
{
    if (nullptr == socket_obj.get())
    {
        return r_socket_proxy_ret_t::NULL_PTR;
    }

    if (socket_obj->m_socket_fd == INVALID_SOCKET_FD)
    {
        return r_socket_proxy_ret_t::INVALID_SOCKET_FD;
    }

    if (0 == message.size())
    {
        return r_socket_proxy_ret_t::NO_DATA_CAN_BE_SENT;
    }

    std::lock_guard<std::mutex> lg{socket_obj->m_mutex};

    ssize_t send_num = write(socket_obj->m_socket_fd, message.data(), message.size());
    if (send_num != message.size())
    {
        //TODO Make Sure ALL Data is sent
        return r_socket_proxy_ret_t::TO_SEND_DATA_IS_FAILED;
    }

    LOG_DBG() << "To send Message is success";
    return r_socket_proxy_ret_t::OK;
}

void r_socket_ipv4_tcp_partner::close_socket(const r_socket::ptr socket_obj)
{
    if (nullptr == socket_obj.get())
    {
        return;
    }

    if (socket_obj->m_socket_fd == INVALID_SOCKET_FD)
    {
        return;
    }

    close(socket_obj->m_socket_fd);
    socket_obj->m_socket_fd = INVALID_SOCKET_FD;
    r_socket_obj_manager::get_instance()->remove_socket_obj(socket_obj->m_socket_id);
}

}